(function (fruit, util, ui) {
    var localeCompare = String.prototype.localeCompare;
    var Binding = fruit.Binding;

    fruit.define('fruit.ui.CollectionView', {
        events:['collectionChanged'],
        properties:{
            collection:{
                getter:function () {
                    return this._collection;
                },
                setter:function (value) {
                    if (this._collection != value) {
                        var c = this._collection;
                        if (c && c.off) {
                            c.off('collectionChanged', this._onCollectionChanged, this);
                        }

                        c = this._collection = value;

                        if (c && c.on) {
                            c.on('collectionChanged', this._onCollectionChanged, this);
                        }
                    }
                },
                observable:true
            }
        },
        methods:{
            init:function (collection) {
                if (!(collection instanceof fruit.Collection)) {
                    collection = new fruit.Collection(collection);
                }
                this.collection(collection);
                this._data = this.collection()._data.slice(0);
            },
            getItem:function (index) {
                return this._data[index];
            },
            forEach:function (callback, context) {
                util.forEach(this._data, callback, context);
            },
            filter:function (fn) {
                this._filterFn = fn;
                this.refresh();
            },
            sort:function (fn, des, num) {
                this._sortFn = typeof fn == "function" ? fn :
                    des ?
                        function (a, b) {
                            var v1 = Binding.getByPath(a, fn),
                                v2 = Binding.getByPath(b, fn)

                            if (v1 == v2) {
                                return 0;
                            }
                            else if (v1 == null) {
                                return 1;
                            }
                            else if (v2 == null) {
                                return -1;
                            }

                            if (num) {
                                return v2 - v1;
                            }
                            else {
                                return localeCompare.call(v2, v1);
                            }
                        } :
                        function (a, b) {
                            var v1 = Binding.getByPath(a, fn),
                                v2 = Binding.getByPath(b, fn)

                            if (v1 == v2) {
                                return 0;
                            }
                            else if (v1 == null) {
                                return -1;
                            }
                            else if (v2 == null) {
                                return 1;
                            }

                            if (num) {
                                return v1 - v2;
                            }
                            else {
                                return localeCompare.call(v1, v2);
                            }
                        };

                this._updateData();
                this.notifyCollectionChanged({
                    action:'sort',
                    index:0
                });
            },
            reset:function () {
                this._filterFn = null;
                this._sortFn = null;
                this.refresh();
            },
            refresh:function () {
                this._updateData();
                this.notifyCollectionChanged({
                    action:'reset',
                    index:0
                });
            },
            notifyCollectionChanged:function (data) {
                this.fire('collectionChanged', data);
            },
            _updateData:function () {
                var data = this._data = this.collection()._data.slice(0);
                var filterFn = this._filterFn;
                var sortFn = this._sortFn;
                var result, item;
                if (filterFn) {
                    result = [];
                    for (var i = 0, length = data.length; i < length; i++) {
                        item = data[i];
                        if (filterFn(item, i)) {
                            result.push(item);
                        }
                    }
                }
                else {
                    result = data;
                }

                if (sortFn) {
                    result.sort(sortFn);
                }

                this._data = result;
            },
            _onCollectionChanged:function (sender, event) {
                if (event.action == 'add') {
                    this._updateData();
                    this.notifyCollectionChanged({
                        action:'add',
                        item:event.item,
                        index:util.indexOf(this._data, event.item)
                    });
                }
                else if (event.action == 'remove') {
                    this.notifyCollectionChanged({
                        action:'remove',
                        item:event.item
                    });
                }
                else if (event.action == 'reset') {
                    this._updateData();
                    this.notifyCollectionChanged({
                        action:'reset',
                        index:0
                    });
                }
                else if (event.action == 'sort') {
                    this._updateData();
                    this.notifyCollectionChanged({
                        action:'sort',
                        index:0
                    });
                }
            }
        }
    });

})(fruit, fruit.util, fruit.ui);
